﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.TeamFoundation;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Deployment.TeamFoundation.Entity;
using VersionControlClient = Microsoft.TeamFoundation.VersionControl.Client;
using WorkItemTrackingClient = Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace Deployment.TeamFoundation.Communication
{
    /// <summary>
    /// Classe que manipula os eventos do Workspace
    /// </summary>    
    public class WorkspaceClient : CommunicationBase
    {
        private static WorkspaceClient instance;
        private VersionControlServer _versionControl = null;

        protected WorkspaceClient()
        {
            _versionControl = Communication.VersionControl.Instance.GetVersionControlServer();
        }

        #region Singleton

        public static WorkspaceClient Instance
        {
            get
            {
                if (instance == null)
                {
                    Mutex mutex = new Mutex();
                    mutex.WaitOne();

                    if (instance == null)
                        instance = new WorkspaceClient();

                    mutex.Close();
                }
                return instance;
            }
        }
        #endregion Singleton

        #region Private Methods

        /// <summary>
        /// Obtém ou cria um workspace temporário
        /// </summary>
        /// <param name="versionControl">Servidor de Versão</param>
        /// <param name="workspaceName">Nome do workspace</param>
        /// <returns>Um workspace</returns>
        private Workspace GetOrCreateTemporaryWorkspace(string workspaceName)
        {
            if (string.IsNullOrEmpty(workspaceName))
                throw new ArgumentNullException("workspaceName");

            Workspace workspace = null;

            if (string.IsNullOrEmpty(workspaceName))
            {
                workspace = CreateTemporaryWorkspace();
            }
            else
            {
                try
                {
                    workspace = _versionControl.GetWorkspace(workspaceName, _versionControl.AuthenticatedUser);
                }
                catch
                {
                    workspace = null;
                }
            }

            if (workspace == null)
            {
                workspace = _versionControl.CreateWorkspace(workspaceName, _versionControl.AuthenticatedUser);
            }

            return workspace;
        }

        /// <summary>
        /// Cria um Workspace temporário
        /// </summary>
        /// <param name="versionControl">Servidor de Versão</param>
        /// <returns>Workspace temporário</returns>
        private Workspace CreateTemporaryWorkspace()
        {
            Random random = new Random();
            random.Next();
            string name = random.Next().ToString() + "DeploymentTemporaryWorkspace";

            return _versionControl.CreateWorkspace(name, _versionControl.AuthenticatedUser);
        }

        #endregion Private Methods

        #region Public Methods

        /// <summary>
        /// Obtém um código fonte
        /// </summary>
        /// <param name="workspaceName">Nome do Workspace</param>
        ///<param name="sourcePath">Caminho no Team System do Código Fonte</param>
        ///<param name="targetPath">Caminho no qual o Código Fonte será baixado</param>
        ///<param name="destroyWorkspace">Indica se o workspace será destruido logo após os arquivos serem baixados</param>
        public void GetSource(string workspaceName, string sourcePath, string targetPath, bool destroyWorkspace, TFSGetType getType)
        {
            if (string.IsNullOrEmpty(workspaceName))
                throw new ArgumentNullException("workspaceName");

            if (string.IsNullOrEmpty(sourcePath))
                throw new ArgumentNullException("sourcePath");

            if (string.IsNullOrEmpty(targetPath))
                throw new ArgumentNullException("targetPath");

            string newSourcePath = "";
            Workspace workspace = null;
            ItemSet itemSet = null;

            try
            {
                workspace = GetOrCreateTemporaryWorkspace(workspaceName);

                if (getType == TFSGetType.File)
                {
                    newSourcePath = string.Join("/", sourcePath.Split('/'), 0, sourcePath.Split('/').Length - 1);
                    MappingWorkspace(workspace, newSourcePath, targetPath);
                }
                else
                    MappingWorkspace(workspace, sourcePath, targetPath);


                if (getType == TFSGetType.File)
                {
                    string fileName = sourcePath.Split('/').Last().ToLower();

                    itemSet = workspace.VersionControlServer.GetItems(newSourcePath, RecursionType.Full);

                    Item item = (from it in itemSet.Items
                                 where it.ServerItem.Split('/').Last().ToLower().Equals(fileName)
                                 select it).ToList()[0];

                    workspace.Get(new GetRequest(item.ServerItem, RecursionType.None, VersionSpec.Latest), GetOptions.Overwrite);
                }
                else
                {
                    //#if (DEBUG)
                    workspace.Get();
                    //#else
                    //itemSet = workspace.VersionControlServer.GetItems(sourcePath, RecursionType.Full);

                    //foreach (Item item in itemSet.Items)
                    //{
                    //    Console.WriteLine(item.ServerItem);
                    //    workspace.Get(new GetRequest(item.ServerItem, RecursionType.None, VersionSpec.Latest), GetOptions.Overwrite);
                    //}
                    //#endif
                }
            }
            finally
            {
                if (workspace != null && destroyWorkspace)
                    workspace.Delete();
            }
        }

        /// <summary>
        /// Efetua checkin nas alterações efetuadas no workspace
        /// </summary>
        /// <param name="workspaceName">Nome do Workspace</param>
        /// <param name="message">Mensagem para o checkib</param>
        /// <param name="destroyWorkspace">Indica se o Workspace será excluído</param>
        public void CheckIn(string workspaceName, string message, bool destroyWorkspace)
        {
            if (string.IsNullOrEmpty(workspaceName))
                throw new ArgumentNullException("workspaceName");

            Workspace workspace = GetOrCreateTemporaryWorkspace(workspaceName);
            workspace.CheckIn(workspace.GetPendingChanges(), message);
            if (destroyWorkspace)
                workspace.Delete();
        }

        /// <summary>
        /// Mapeia um Workspace a um caminho físico
        /// </summary>
        /// <param name="workspace">Workspace a ser mapeado</param>
        /// <param name="localItemMapping">Caminho físico</param>
        public void MappingWorkspace(Workspace workspace, string serverLocation, string localItemMapping)
        {
            if (workspace == null)
                throw new ArgumentNullException("workspace");

            if (string.IsNullOrEmpty(localItemMapping))
                throw new ArgumentNullException("localItemMapping");

            if (!workspace.IsLocalPathMapped(localItemMapping))
            {
                WorkingFolder mapping = new WorkingFolder(serverLocation, localItemMapping, WorkingFolderType.Map);
                workspace.CreateMapping(mapping);
            }
        }


        /// <summary>
        /// Adiciona um arquivo ou pasta ao workspace
        /// </summary>
        /// <param name="workspaceName">Nome do Workspace</param>
        /// <param name="path">Caminho do arquivo ou pasta</param>
        public void AddFileOrFolder(string workspaceName, string serverPath, string localPath)
        {
            if (string.IsNullOrEmpty(workspaceName))
                throw new ArgumentNullException("workspaceName");

            if (string.IsNullOrEmpty(localPath))
                throw new ArgumentNullException("localPath");

            if (string.IsNullOrEmpty(serverPath))
                throw new ArgumentNullException("serverPath");

            Workspace workspace = GetOrCreateTemporaryWorkspace(workspaceName);
            MappingWorkspace(workspace, serverPath, localPath);
            workspace.PendAdd(localPath, true);
            //workspace.Delete();

            this.CheckIn(workspaceName, "", true);
        }

        /// <summary>
        /// Exclui um workspace
        /// </summary>
        /// <param name="workspaceName">Nome do Workspace</param>
        public void DeleteWorkspace(string workspaceName)
        {
            if (string.IsNullOrEmpty(workspaceName))
                throw new ArgumentNullException("workspaceName");

            Workspace workspace = GetOrCreateTemporaryWorkspace(workspaceName);
            workspace.Delete();
        }

        #endregion Public Methods
    }
}

